Skip to content

PMM-15205 Ship SEP embedded in PMM (Tech Preview) - #5884

Draft
yyyyyyyan wants to merge 27 commits into
mainfrom
PMM-15205-sep-fb
Draft

PMM-15205 Ship SEP embedded in PMM (Tech Preview)#5884
yyyyyyyan wants to merge 27 commits into
mainfrom
PMM-15205-sep-fb

Conversation

@yyyyyyyan

@yyyyyyyan yyyyyyyan commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Ticket number: PMM-15205

Feature build: perconalab/pmm-server-fb:PR-4500-2c43912 — built by
Percona-Lab/pmm-submodules#4500 from submodules commit 2c43912, pinning this
branch at 53521917d (2026-09-03).

How to tell whether a PR is in that build. The submodules pin follows this
branch's tip at build time, so the image tag names the submodules commit, not
the PMM one. The build's ci.yml records the PMM commit and date it was cut
from, and the line above repeats it. For anything merged here since, ask git:

git merge-base --is-ancestor <the PR's merge commit> 53521917d && echo "in the FB"

Re-cut the build after merging anything you need exercised, and refresh both
that ci.yml block and this line.

Integration branch for the PMM + SEP Integration (Tech Preview) epic. Every
child ticket of PMM-15205 lands here first, so main sees one reviewable change
with the whole Tech Preview in it rather than a half-wired feature spread over a
dozen merges.

This PR is a draft and stays that way until the epic closes. It is open now
so the accumulated diff is reviewable while the remaining children land, not
because it is ready.

How this branch is used

PRs for PMM-15205 children target PMM-15205-sep-fb (or stack on a sibling
whose own base is this branch). They are squash-merged here, one commit per
ticket. This branch is then merged to main once.

The branch was previously used only to compile feature builds — it was
re-derived from scratch whenever a build was needed, so it carried duplicate and
superseded copies of work that was still in review. It has been rebuilt as a
linear history on current main, one commit per ticket, and its tree verified
byte-identical to the last feature-build derivation plus the current heads of
#5759 and #5762.

Composition

Ticket What it adds
PMM-15216 The SEP frontend, vendored into the UI workspace as ui/packages/sep/* and mounted on /sep (4 commits: the migration, a peak-ui alignment, form/layout fixes, and a dev-proxy Origin fix)
PMM-15293 The embedded UI exchanges the PMM session for a per-user SEP bearer instead of an injected static token
PMM-15294 ServiceNow connection settings submitted to SEP
PMM-15337 Support diagnostics gated on ServiceNow setup
PMM-15358 Per-app write controls hidden from non-admin sessions
PMM-15359 Failed SEP UI actions reported in SEP's own component tree
PMM-15281 SEP's nav entries and pages rendered only when the integration is enabled
PMM-15384 The SEP apps grouped under a Management sidebar section
PMM-15397 The Collect panel hidden from Viewers and Editors
PMM-15405 Support diagnostics kept readable when ServiceNow delivery is unavailable
PMM-15407 SEP enablement reported in PMM Server telemetry
PMM-15424 Management sidebar icons and grouping
PMM-15279 (#5759) The /sep/ nginx reverse proxy, productized out of the harness overlay
PMM-15316 (#5762) SEP's SECRET_KEY and database credentials published as secret files; the database password generated when unset
PMM-15414, PMM-15415, PMM-15437, PMM-15438, PMM-15439, PMM-15440 (#5886) The vendored SEP frontend synced to SEP main c16578dfe — support-case autocomplete, the unlaunchable status, delivery-step naming, the executor co-location warning, per-task display names, and a plain-string setting class

PMM-15238 (#5700) and PMM-15288 (#5728) are already on main and are not part of
this diff. PMM-15280 (#5755) was closed — the Grafana service account moved to
the SEP side.

Everything here is behind PMM_ENABLE_SEP

With the flag unset the shipped backend delta is one inert glob include in
pmm.conf; nginx renders no drop-in, no secret files are written, and no SEP
database is provisioned. The SEP UI is additionally gated on the sepEnabled
setting (PMM-15281), which defaults to false, so the nav entry and its routes
stay hidden.

Please merge with a merge commit, not a squash

The repo's default is squash-and-merge, which would collapse the whole epic —
13 tickets and several thousand reviewed lines — into a single main commit and
discard the per-ticket attribution, including the Co-authored-by trailers that
credit everyone who worked on the UI migration. A merge commit keeps the
per-ticket history bisectable on main.

Testing

Each child ticket carries its own testing evidence on its own PR; this
description does not restate it.

What is specific to the integration branch:

  • shellcheck -s bash and bash -n are clean on entrypoint.sh, sep-secrets
    and postgres-sep at the branch tip.
  • go test ./managed/utils/envvars/... passes. In managed/services/server,
    TestSepConfigFiles passes; TestFiles fails outside a container because it
    reads /etc/nginx/nginx.conf — it fails identically on main, so it is
    neither covered by nor broken by this branch.
  • The branch tree was diffed against the previous feature-build derivation:
    identical apart from the two backend PRs being at their current reviewed heads
    rather than superseded copies.

Two defects were found and fixed on this branch, and they are the reason it
needs a PR at all.

The SEP log viewer was crashing on any task in stale status whose logs were
open: FinishStatus never listed it while the SSE finish event forwards the
backend's status verbatim, so the badge's map returned undefined and reading
.color off it threw. Fixed in #5886, which also makes the badge render an
unrecognised status as raw text rather than indexing into nothing.

The second was found by CI on this PR's first run. PMM-15281 made sepEnabled a required field of
ReadonlySettings; src/api/__mocks__/settings.ts, which has to satisfy that
type, only reached main on 2026-09-02 with #5744, after every UI change on
this branch. They met for the first time when the branch last merged main.
The merge was textually clean and left tsc failing with TS2741 — and nothing
caught it, because the branch had no pull request and so had never been built by
CI.

Before merge

  • A green Feature Build, exercising the shipped image path — the /srv/sep
    mountpoint and the rendered nginx drop-in only exist in a real build.
  • End-to-end verification against the paired SEP side-car.
  • The remaining PMM-15205 children merged into this branch.
  • API Docs updated — not applicable, no API endpoints added, removed or altered.

https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT

yyyyyyyan and others added 17 commits September 3, 2026 14:34
Vendors the SEP frontend into the PMM UI workspace under ui/packages/sep/*
and mounts it on the /sep route, so the side-car's screens render inside PMM's
shell instead of its own.

Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
The embedded UI exchanges the PMM session for a SEP bearer rather than
carrying an injected static token.

Co-authored-by: Fábio Silva <ffjs1993@gmail.com>
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Fabio Silva <ffjs1993@gmail.com>
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Fabio Silva <ffjs1993@gmail.com>
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
changeOrigin rewrites Host and Referer but not Origin, so Grafana's CSRF check
rejected state-changing requests through the dev proxy with a 403.

Co-authored-by: Fabio Silva <ffjs1993@gmail.com>
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Peter Addo <peter.addo@percona.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Co-authored-by: Ignacio Durand <nachodurand@gmail.com>
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
PMM-15281 made sepEnabled a required field of ReadonlySettings. The mock that
has to satisfy that type, src/api/__mocks__/settings.ts, only reached main on
2026-09-02 with PMM-15302 (#5744) - after every UI checkpoint on this branch -
so the two met for the first time when the branch last merged main.

The merge was textually clean and left a type error behind: tsc fails with
TS2741 on READONLY_SETTINGS_MOCK. Nothing caught it because the branch had no
pull request of its own, so CI had never run on it.

false matches the default the provider ships and the value testUtils.tsx
already uses.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Ships the /sep/ nginx reverse-proxy configuration as first-class shipped configuration, replacing the hand-maintained overlay in SEP's feature-build harness. Gated on PMM_ENABLE_SEP; with the flag unset the only shipped delta is one inert glob include.

Adds PMM_SEP_ADDRESS (default sep:9000), validated before interpolation, with the resolver read from /etc/resolv.conf so the AMI and OVF images work under Podman's aardvark-dns.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 44.23%. Comparing base (31318c7) to head (5352191).
⚠️ Report is 165 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5884      +/-   ##
==========================================
+ Coverage   43.59%   44.23%   +0.63%     
==========================================
  Files         415      304     -111     
  Lines       43134    33119   -10015     
==========================================
- Hits        18804    14649    -4155     
+ Misses      22454    16950    -5504     
+ Partials     1876     1520     -356     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

yyyyyyyan and others added 10 commits September 3, 2026 16:12
…5762)

With PMM_ENABLE_SEP set, pmm-server writes SEP's deployment secrets into /srv/sep as files named after the canonical SEP settings name each supplies: SECRET_KEY, SEP__DATABASE__PASSWORD, INVENTORY__DATABASE__PASSWORD and TASKS__DATABASE__PASSWORD.

SECRET_KEY is generated once and persisted, so restarting PMM keeps SEP sessions valid; the database passwords are rewritten every start so rotation takes effect on the next restart. PMM_SEP_POSTGRES_PASSWORD is now optional - PMM generates and persists one when it is unset, so a bare docker compose up needs no secret chosen in advance.

Also carries the /srv/sep mountpoint and the pmm-sep volume, which the closed #5755 used to supply.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Refreshes the four vendored spec files from SEP main c16578dfe and regenerates
the TS client. The previous sync watermark was 249f6738a (2026-08-25); 19 SEP
commits have touched the mirrored packages since.

Copied wholesale and formatted rather than hand-spliced, per the porting notes.
main.json's raw diff was pure reflow and collapses to nothing once oxfmt runs.

Endpoint-shape audit over the drift, which is the check that matters here
rather than the commit count:

  - All nine bare-array apiClient.get call sites still receive arrays:
    /api/admin/apps/, /api/apps/, /api/sep/hosts/,
    /api/sep/services/{id}/schemas, /api/sep/schemas/{id}/tables,
    /api/apps/atw/, /execution-events/{id}, and the two that already
    normalize either shape.
  - Three endpoints were removed, all inventory writes (SEP-1856). PMM does
    not vendor the inventory app and renders it generically from the schema
    the side-car serves, which no longer declares those forms or actions, so
    nothing in PMM reaches them.
  - Sixteen endpoints were added; all are additive.

This commit alone leaves @sep/api failing check-types, because SettingClassEnum
is gone from the spec. PMM-15440 immediately following resolves it.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
SEP-1825 lets an app declare its own settings class without editing core or
migrations, so the class travels as the Pydantic class __name__ - "SEPSettings",
"AlertsSettings" - rather than a member of a closed enum, and SettingClassEnum
is gone from the spec.

Not optional: with the refreshed spec, aliasing the removed schema is a
compile error.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
SEP-1779 lifted the duplicated search debounce into @sep/framework. It landed
before the 249f6738a sync watermark, but the sync that set that watermark
audited spec and endpoint shape rather than exports, so PMM never picked it up
and the hook is absent from the vendored framework.

Surfaced as a hard dependency: SEP-1956's Send dialog imports useDebouncedValue
from @sep/framework, so the next commit does not compile without it.

Ports the hook and its test only. PMM's own duplicated debounces -
CollectPane's SNIPPET_SEARCH_DEBOUNCE_MS and ScriptPreviewField's DEBOUNCE_MS -
are left alone; collapsing them onto this hook is SEP-1779's refactor and has
no bearing on the drift being closed here.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
…ider

Ports SEP-1956. The Send dialog resolves support case references against the
delivery provider as the user types instead of requiring an exact reference,
falling back to a plain text input when the deployment declares no case-search
section or the provider errors.

atw_config gained case_search_available, so useAtwConfig's error fallback
carries it too - without that the fallback no longer satisfies AtwConfig and
the regenerated client fails to compile.

SendDialog.tsx was byte-identical to SEP's pre-change copy once run through
PMM's formatter, so it is taken wholesale rather than hand-merged.

The test's case-search helper is indexed rather than destructured with a tuple
annotation: PMM typechecks the ATW tests where SEP does not, and mock.calls is
not a fixed-length tuple.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Ports SEP-1943's frontend arm. TaskHistoryStatusEnum gained UNLAUNCHABLE for an
execution whose Nomad node could not launch the requested interpreter, so the
history badge, the log-viewer badge and the ATW resend set all learn it. The
compiler enforced the first of those against the regenerated union.

The second half is a crash that predates SEP-1943 and is fixed on the way past.
FinishStatus never listed 'stale' while the SSE finish event forwards the
backend's status verbatim, so MAP['stale'] was undefined and reading .color off
it threw - blanking the whole log viewer for any stale task whose logs were
open. 'stale' joins the union and the map, and the badge now renders an
unrecognised status as its raw text rather than indexing into nothing, so the
next member added backend-side degrades instead of crashing.

unlaunchable and executor-gone deliberately share one entry: to an operator both
mean the node could not run this, not that the script failed.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Ports SEP-1942's frontend arm. A send log's step entries gained a `kind`
discriminator - resolution or upload - and `failed` joins the step status, so a
failed send says which step ended it rather than only that it ended.

`kind` is optional only for history: the backend writes it on every entry it
records now, but rows persisted before it existed carry entries without it.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Ports the frontend arm of SEP-1892. Scheduled tasks carry an optional
display_name alongside name; PluginTask did not declare it, so the friendlier
label the side-car sends was dropped on the floor.

PMM's copy calls this PluginTask where SEP calls it AppTask - the pre-rename
vocabulary the vendored packages still use.

The rest of SEP-1892 is inventory tombstone collection: backend-only, shipped
by the side-car.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
Ports SEP-1818. A host field may now name a target_service; when it does, the
selector shows a non-blocking warning if the chosen executor's address differs
from the address of the node the service runs on. Choosing a non-co-located
executor stays legal - it is usually a mistake, and it used to fail late and
unhelpfully.

Co-location is compared on address alone: Nomad node names and inventory
display names are independent namespaces, so two hosts sharing an address are
one machine. An absent address is unknown rather than different, so the warning
stays silent whenever co-location cannot be established.

HostSelector.tsx had diverged too far from SEP's copy for a wholesale take -
272 lines apart after running SEP's baseline through PMM's formatter - so the
change is applied by hand. isHostMismatch and its test are taken verbatim.
Only HostField gains target_service; PMM vendors no MultiHostField.

Claude-Session: https://claude.ai/code/session_01RFUiQUpHgyaK6ozEQJ8wmT
Signed-off-by: Yan Orestes <yan.orestes@percona.com>
PMM-15205 Sync the vendored SEP frontend to c16578dfe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant